package com.ms.jsf;

import com.ms.domain.validator.ValidationService;
import com.ms.exception.DpwcConfigException;
import com.ms.exception.DpwcException;
import com.ms.exception.DpwcSystemException;
import com.ms.exception.ExceptionUtils;
import com.ms.seguridad.UserInfo;
import com.ms.seguridad.support.ViewInfoMgr;
import com.ms.services.commons.schema.AuditInfo;
import org.primefaces.context.RequestContext;
import org.primefaces.event.CloseEvent;
import org.primefaces.visit.ResetInputVisitCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitHint;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.AjaxBehaviorEvent;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.EnumSet;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

/**
 * User: gmc
 * Date: 23/03/13
 */
public abstract class JsfBeanBase {
    protected final Logger LOG = LoggerFactory.getLogger(getClass());

    private String MSG_RESOURCEBUNDLE_NAME = "messages";
    private String ERROR_MSG_RESOURCEBUNDLE_NAME = "errorMessages";

    @Autowired
    ErrorMessageResolver errorMessageResolver;

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    ValidationService validationService;


    // Last action event
    protected ActionEvent actionEvent;

    protected String pageSufix = "";
    private ViewInfoMgr viewInfoMgr;

    protected void validate(Object object) {
        validationService.validate(object);
    }

    protected void validateBasic(Object object) {
        validationService.validateFirstLevel(object);
    }

    protected final String getMessage(String key, Object... parameters) {
        String text = null;
        try {
            text = getResourceBundle().getString(key);
        } catch (MissingResourceException e) {
            text = key;
        }
        if (parameters != null && parameters.length > 0) {
            MessageFormat messageFormat = new MessageFormat(text);
            text = messageFormat.format(parameters);
        }
        return text;
    }

    protected final ResourceBundle getResourceBundle() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ResourceBundle bundle = facesContext.getApplication().
                getResourceBundle(facesContext, MSG_RESOURCEBUNDLE_NAME);
        return bundle;
    }

    protected final ResourceBundle getErrorResourceBundle() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ResourceBundle bundle = facesContext.getApplication().
                getResourceBundle(facesContext, ERROR_MSG_RESOURCEBUNDLE_NAME);
        return bundle;
    }

    /**
     * Show the modal sent as actionEvent attribute
     */
    protected final void showModal() {
        String dialogWv = getDialogWv();
        showOrHideModal(dialogWv, true);
    }

    /**
     * Hide the modal sent as actionEvent attribute
     */
    protected final void hideModal() {
        String dialogName = getDialogWv();
        showOrHideModal(dialogName, false);
    }

    private String getDialogWv() {
        String dialogWv = (String) actionEvent.getComponent().getAttributes().get(ViewConstant.DIALOG_WV);
        if (!StringUtils.hasText(dialogWv)) {
            throw new DpwcConfigException("Debe enviar como parametro el valor del atributo widgetVar del Dialog");
        }
        if (!dialogWv.startsWith("wv")) {
            throw new DpwcConfigException("El valor del atributo widgetVar del Dialog debe comenzar con: wv");
        }
        return dialogWv;
    }

    protected String getAction() {
        String action = (String) actionEvent.getComponent().getAttributes().get("accion");
        return action;
    }


    protected void showOrHideModal(String dialogWv, boolean show) {
        RequestContext context = RequestContext.getCurrentInstance();
        String command = "PF('"+dialogWv+"').hide()" ;
        if (!show) {
            //PF('wstatusDialog').show();
            context.execute(command);
            return;
        }
        command = "PF('"+dialogWv+"').show()" ;
        context.execute(command);
        String dlgPrefix = ViewConstant.PREFIX_DIALOG_ID;
        String zoneToUpdate = dlgPrefix + dialogWv.substring(2);
        if (dialogWv.equals(ViewConstant.WV_CUSTOM_MESSAGE)) {
            context.update(ViewConstant.PNL_CUSTOM_MESSAGE);
            return;
        }
//        toUpdate.add(zoneToUpdate);
//        context.update(toUpdate);
        context.update(zoneToUpdate);

    }

    public final void addErrorMessage(DpwcException dpwcException) {
        String errorMessage = errorMessageResolver.getErrorMessage(dpwcException, getErrorResourceBundle());
        getViewInfoMgr().setMessageInfo("error", errorMessage);
        showOrHideModal(ViewConstant.WV_CUSTOM_MESSAGE, true);
    }

    protected final void addErrorMessage(String key, Object... parameters) {
        addMessage(key, FacesMessage.SEVERITY_ERROR, parameters);
    }

    public final void addFatalDpwcErrorMessage(DpwcSystemException throwable) {
        String iconMessage = "error";
        String errorMsg = "Error de Sistema:" + throwable.getMessage();
        String fullMsg = throwable.getFullErrorMsg();
        if (!StringUtils.hasText(fullMsg)) {
            fullMsg = ExceptionUtils.getFullExceptionMsg(throwable);
        }
        getViewInfoMgr().setMessageInfo(iconMessage, errorMsg, fullMsg);
        showOrHideModal(ViewConstant.WV_CUSTOM_MESSAGE, true);
    }

    public final void addErrorMessageWithDetails(DpwcException throwable) {
        String iconMessage = "error";
        String errorMsg = throwable.getMessage();
        String fullMsg = ExceptionUtils.getFullExceptionMsg(throwable);
        getViewInfoMgr().setMessageInfo(iconMessage, errorMsg, fullMsg);
        showOrHideModal(ViewConstant.WV_CUSTOM_MESSAGE, true);
    }


    public final void addFatalErrorMessage(Throwable throwable) {
        String iconMessage = "error";
        String errorMsg = "Error de Sistema";
        String fullMsg = ExceptionUtils.getFullExceptionMsg(throwable);
        getViewInfoMgr().setMessageInfo(iconMessage, errorMsg, fullMsg);
        showOrHideModal(ViewConstant.WV_CUSTOM_MESSAGE, true);
    }

    protected final void addInfoMessage(String key, Object... parameters) {
        addMessage(key, FacesMessage.SEVERITY_INFO, parameters);
    }

    protected final void addWarnMessage(String key, Object... parameters) {
        addMessage(key, FacesMessage.SEVERITY_WARN, parameters);
    }

    private void addMessage(String key, FacesMessage.Severity severity, Object... parameters) {
        String message = "";
        if (severity.getOrdinal() == FacesMessage.SEVERITY_FATAL.getOrdinal() ||
                severity.getOrdinal() == FacesMessage.SEVERITY_ERROR.getOrdinal()) {
            message = errorMessageResolver.getErrorMessage(key, parameters);
        } else {
            message = getMessage(key, parameters);
        }
        if (severity == null) {
            severity = FacesMessage.SEVERITY_INFO;
        }
        String iconMessage = "info";
        if (severity.getOrdinal() == FacesMessage.SEVERITY_FATAL.getOrdinal()) {
            iconMessage = "error";
        } else if (severity.getOrdinal() == FacesMessage.SEVERITY_ERROR.getOrdinal()) {
            iconMessage = "error";
        } else if (severity.getOrdinal() == FacesMessage.SEVERITY_INFO.getOrdinal()) {
            iconMessage = "info";
        } else if (severity.getOrdinal() == FacesMessage.SEVERITY_WARN.getOrdinal()) {
            iconMessage = "warn";
        }
        getViewInfoMgr().setMessageInfo(iconMessage, message);
        showOrHideModal(ViewConstant.WV_CUSTOM_MESSAGE, true);
    }


    public void setActionEvent(ActionEvent actionEvent) {
        this.actionEvent = actionEvent;
    }

    public String getPageSufix() {
        if (!StringUtils.hasText(pageSufix)) {
            throw new DpwcConfigException("Debe setear pageSufix en el jsfBean:" + this);
        }
        return pageSufix;
    }

    public void setPageSufix(String pageSufix) {
        this.pageSufix = pageSufix;
    }

    protected void goToPage(String page) {
        getViewInfoMgr().goToPage(page);
        try {
            showNewPage(page);
        } catch (IOException e) {
            LOG.error("Problems at going to page:" + page, e);
            throw new DpwcSystemException("Problems at going to page:" + page + " " + e.getMessage(), e);
        }
    }

    protected void showNewPage(String pageWV) throws IOException {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        HttpServletResponse response = (HttpServletResponse) context.getResponse();
        HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        String contextPath = req.getContextPath();
        response.sendRedirect(contextPath + pageWV);
        FacesContext.getCurrentInstance().responseComplete();
    }


    public void handleCloseDlg(AjaxBehaviorEvent ajaxBehaviorEvent) {
        CloseEvent event = (CloseEvent) ajaxBehaviorEvent;
        FacesContext context = FacesContext.getCurrentInstance();
        EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
        VisitContext visitContext = VisitContext.createVisitContext(context, null, hints);
        VisitCallback visitCallback = new ResetInputVisitCallback();
        UIComponent source = event.getComponent();
        for (UIComponent uiComponent : source.getChildren()) {
            UIComponent targetComponent = uiComponent;
            targetComponent.visitTree(visitContext, visitCallback);
        }
    }


    protected ViewInfoMgr getViewInfoMgr() {
        if (viewInfoMgr == null) {
            viewInfoMgr = (ViewInfoMgr) applicationContext.getBean("viewInfoMgr");
        }
        return viewInfoMgr;
    }

    protected UserInfo getUserInfo() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        UserInfo userInfo = (UserInfo) auth.getPrincipal();
        return userInfo;
    }

    protected AuditInfo getAuditInfo() {
        return getUserInfo().getAuditInfo();
    }

    protected void close() {
        getViewInfoMgr().close(getClass().getSimpleName());
    }

}
